package cn.hzc.fortess.system.controller;


import cn.hzc.fortess.core.common.ResponseData;
import cn.hzc.fortess.core.common.annotion.RequestPermission;
import cn.hzc.fortess.core.common.constant.Const;
import cn.hzc.fortess.core.common.BizErrorEnum;
import cn.hzc.fortess.core.common.exception.ServiceException;
import cn.hzc.fortess.core.shiro.ShiroKit;
import cn.hzc.fortess.system.common.EnableStatus;
import cn.hzc.fortess.system.entity.*;
import cn.hzc.fortess.system.service.*;
import cn.hzc.fortess.system.vo.DataVO;
import cn.hzc.fortess.system.vo.MenuDataVO;
import cn.hzc.fortess.system.vo.ResourceAttrVO;
import com.google.common.collect.Lists;
import cn.hzc.fortess.system.node.ZTreeNode;
import cn.hzc.fortess.system.page.Pagination;
import cn.hzc.fortess.system.search.RoleSearch;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Api(tags = {"角色管理"})
@Controller
@RequestMapping("/sam/role")
public class RoleController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(RoleController.class);


    @Autowired
    private RoleService roleService;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private UserService userService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private ResourceAttrService resourceAttrService;
    @Autowired
    private LesseeService lesseeService;

    @ApiIgnore
    @RequestMapping(value = "", method = RequestMethod.GET)
    public String index() {
        setAttr("projects", projectService.getUserProject());
        return buildToView("index.html");
    }

    @ApiIgnore
    @RequestMapping("/add")
    public String addToView(@RequestParam("projectId") Integer projectId) {
        if (projectId == null) {
            throw new ServiceException(BizErrorEnum.REQUEST_NULL);
        }
        Role role = new Role();
        role.setProjectId(projectId);
        role.setStatus(EnableStatus.ENABLE.getStatus());
        setAttr("role", role);
        return buildToView("form.html");
    }

    @ApiOperation("创建角色")
    @RequestMapping(value = "/add.json", method = RequestMethod.POST)
    @ResponseBody
    @RequestPermission("sam:role:add")
    public ResponseData create(Role entity) {
        if (Const.ADMIN_ROLE_NAME.equals(entity.getRoleName())
                || Const.PROJECT_ADMIN_ROLE_NAME.equals(entity.getRoleName())) {
            throw new ServiceException(BizErrorEnum.CANT_ADMIN_NAME);
        }
        this.roleService.add(entity);
        return ResponseData.success();
    }

    @ApiIgnore
    @RequestMapping("/edit/{id}")
    public String editToView(@PathVariable(value = "id") Integer id) {
        Role role = roleService.getById(id);
        setAttr("role", role);
        return buildToView("form.html");
    }

    @ApiOperation("编辑角色")
    @RequestMapping(value = "/edit.json", method = RequestMethod.POST)
    @ResponseBody
    @RequestPermission("sam:role:edit")
    public ResponseData edit(Role entity) {
        Role role = roleService.getById(entity.getId());
        if (role.getIsAdmin() == Const.YES) {
            throw new ServiceException(BizErrorEnum.CANT_CHANGE_ADMIN);
        }
        if (Const.ADMIN_ROLE_NAME.equals(entity.getRoleName())) {
            throw new ServiceException(BizErrorEnum.CANT_ADMIN_NAME);
        }
        this.roleService.update(entity);
        return ResponseData.success();
    }

    @ApiOperation("删除角色")
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
    @ResponseBody
    @RequestPermission("sam:role:delete")
    public ResponseData delete(@PathVariable(value = "id") Integer id) {
        log.info("del role ..id {}", id);
        Role role = roleService.getById(id);
        if (role.getIsAdmin() == Const.YES) {
            throw new ServiceException(BizErrorEnum.CANT_DELETE_ADMIN);
        }
        this.roleService.delete(id);
        return ResponseData.success();
    }

    @ApiIgnore
    @RequestMapping(value = "/role_assign/{roleId}")
    public String roleAssign(@PathVariable(value = "roleId") Integer roleId, Model model) {

        model.addAttribute("roleId", roleId);

        final Role role = roleService.getById(roleId);
        final Integer projectId = role.getProjectId();
        if (!Objects.equals(Const.SAM_PROJECT_ID, projectId)) {

            //有数据字段的菜单
            List<MenuDataVO> menus = menuService.getDataMenuList(projectId).stream().map(menu -> {
                MenuDataVO menuDataVO = new MenuDataVO();
                menuDataVO.setMenuId(menu.getId());
                menuDataVO.setMenuName(menu.getResourceName());

                //查询该菜单下配置的字段
                List<DataVO> dataVOS = Lists.newArrayList();
                List<ResourceAttrVO> attrs = resourceAttrService.getRoleResourceAttrList(menu.getId(), null);
                if (attrs != null) {
                    for (ResourceAttrVO attr : attrs) {
                        DataVO dataVO = new DataVO();
                        dataVO.setAttrId(attr.getId());
                        dataVO.setAttrName(attr.getAttrName() + "(" + attr.getAttrCode() + ")");
                        dataVO.setAttrAuth(StringUtils.isBlank(attr.getAttrAuth()) ? "rw" : attr.getAttrAuth());
                        dataVOS.add(dataVO);
                    }
                }

                menuDataVO.setAttrs(dataVOS);
                return menuDataVO;
            }).collect(Collectors.toList());
            model.addAttribute("menus", menus);
        }


        return buildToView("role_assign.html");
    }


    @ApiIgnore
    @RequestPermission("sam:role:auth")
    @RequestMapping(value = "/role_user/{roleId}")
    public String roleUser(@PathVariable(value = "roleId") Integer roleId, Model model) {
        
        model.addAttribute("roleId", roleId);

        return buildToView("role_user.html");
    }


    @ApiOperation("角色用户")
    @RequestMapping(value = "/setRoleUser", method = RequestMethod.POST)
    @ResponseBody
    @RequestPermission("sam:role:auth")
    public ResponseData setRoleUser(@RequestParam("roleId") Integer roleId,
                                    @RequestParam("userIds") String userIds) {

        if (roleId == null || userIds == null) {
            throw new ServiceException(BizErrorEnum.REQUEST_NULL);
        }


        this.roleService.saveRoleUser(roleId, userIds.split(","));


        return ResponseData.success();
    }


    @ApiIgnore
    @RequestPermission("sam:role:auth")
    @RequestMapping(value = "/userTreeListByRoleId/{roleId}", method = RequestMethod.POST)
    @ResponseBody
    public List<ZTreeNode> userTreeByRoleUser(@PathVariable(value = "roleId") Integer roleId) {

        final Role role = roleService.getById(roleId);

        List<Integer> users = userService.getUserByRole(roleId).parallelStream().map(User::getUserId).collect(Collectors.toList());

        //角色所属项目的租户s
        List<Lessee> lessees = lesseeService.getByProjectId(role.getProjectId());

        final List<ZTreeNode> nodes = Lists.newArrayList();

        lessees.stream().forEach(lessee -> {

            if ((!ShiroKit.getUser().isAdministrator())
                    && Objects.equals(Const.SAM_LESSEE_ID, lessee.getId())) {
                return;
            }

            final ZTreeNode root = new ZTreeNode();
            root.setChecked(false);
            root.setId(-Long.parseLong(lessee.getId().toString()));
            root.setName(lessee.getName());
            root.setOpen(true);
            root.setPId(0L);
            root.setChkDisabled(true);
            nodes.add(root);

            List<User> lesseeUsers = userService.getUserByLessee(lessee.getId());
            lesseeUsers.stream().forEach(user -> {
                if (Const.ADMIN_LOGIN_NAME.equals(user.getAccount())) {
                    return;
                }
                final ZTreeNode zTreeNode = new ZTreeNode();
                zTreeNode.setChecked(users.contains(user.getUserId()));
                zTreeNode.setId(Long.parseLong(user.getUserId().toString()));
                zTreeNode.setName(user.getUserName() + "（" + user.getAccount() + "）");
                zTreeNode.setOpen(true);
                zTreeNode.setPId(Long.parseLong(root.getId().toString()));

                nodes.add(zTreeNode);

            });

        });
        return nodes;

    }


    @ApiOperation("获取分页列表")
    @ResponseBody
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @RequestPermission("sam:role:list")
    public Pagination page(RoleSearch search) {
        return this.roleService.getPage(search);
    }

    @ApiOperation("角色授权")
    @RequestMapping(value = "/setAuthority", method = RequestMethod.POST)
    @ResponseBody
    @RequestPermission("sam:role:auth")
    public ResponseData setAuthority(@RequestParam("roleId") Integer roleId,
                                     @RequestParam("ids") String menuIds, //角色菜单权限
                                     @RequestParam(value = "datas", required = false) String datas //角色数据权限
    ) {

        if (roleId == null || menuIds == null) {
            throw new ServiceException(BizErrorEnum.REQUEST_NULL);
        }

        if ((!ShiroKit.getUser().isAdministrator())
                && roleService.getById(roleId).getIsAdmin() == Const.YES) {
            throw new ServiceException(BizErrorEnum.REQUEST_NOT_ALLOW);

        }

        this.roleService.setAuthority(roleId, menuIds.split(","));

        if (StringUtils.isNotBlank(datas)) {
            final List<ResourceAttrVO> attrDataList = Lists.newArrayList();
            for (String data : datas.split("\\|")) {
                if (StringUtils.isBlank(data)) {
                    continue;
                }
                attrDataList.add(buildResourceDataAttr(data));
            }
            this.roleService.setDataAuthority(roleId, attrDataList);
        }

        return ResponseData.success();
    }


    private ResourceAttrVO buildResourceDataAttr(String data) {
        ResourceAttrVO vo = new ResourceAttrVO();
        String[] attrs = data.split(",");
        vo.setResourceId(Integer.parseInt(attrs[0]));
        vo.setId(Integer.parseInt(attrs[1]));
        vo.setAttrAuth(attrs[2]);
        return vo;
    }


    private List<Project> getLesseeProjectList(Integer lesseeId) {
        List<Project> projects = projectService.getAllByLesseeId(lesseeId);
        if (CollectionUtils.isEmpty(projects)) {
            return Lists.newArrayList();
        }
        return projects;
    }

    //用于用户分配角色的树
    @ApiOperation("获取用户角色列表")
    @RequestPermission("sam:user:setRole")
    @RequestMapping(value = "/roleTreeListByUserId/{userId}", method = RequestMethod.POST)
    @ResponseBody
    public List<ZTreeNode> treeByUser(@PathVariable(value = "userId") Integer userId) {
        final User theUser = this.userService.getById(userId);
        //查询该租户下的所有项目，项目下的所有角色，组成树
        final List<Project> projects = getLesseeProjectList(theUser.getLesseeId());
        final List<Integer> userRoles = roleService.getByUser(userId).parallelStream().map(role -> role.getId()).collect(Collectors.toList());

        final List<ZTreeNode> nodes = Lists.newArrayList();
        final ZTreeNode root = ZTreeNode.createParent();
        root.setChecked(false);
        nodes.add(root);

        projects.stream().forEach(project -> {
            final ZTreeNode zTreeNode = new ZTreeNode();
            zTreeNode.setChecked(false);
            zTreeNode.setId(-Long.parseLong(project.getId().toString()));
            zTreeNode.setName(project.getProjectName());
            zTreeNode.setOpen(true);
            zTreeNode.setPId(0L);
            zTreeNode.setChkDisabled(true);
            nodes.add(zTreeNode);
            //查询项目下的角色
            List<Role> projectRoles = roleService.getByProjectId(project.getId());
            log.debug("该项目角色:{}", projectRoles.toString());
            for (Role role : projectRoles) {
                //跳过超级管理员角色
                if (Objects.equals(role.getId(), Const.ADMIN_ROLE_ID)) {
                    continue;
                }

                if ((!ShiroKit.isAdmin()) && role.getIsAdmin() == Const.YES) {
                    //项目管理员不能再授权给其他人
                    //zTreeNodeRole.setChkDisabled(true);
                    continue;
                }

                final ZTreeNode zTreeNodeRole = new ZTreeNode();
                zTreeNodeRole.setChecked(userRoles.contains(role.getId()));
                zTreeNodeRole.setId(Long.parseLong(role.getId().toString()));
                zTreeNodeRole.setName(role.getRoleName());
                zTreeNodeRole.setOpen(true);
                zTreeNodeRole.setPId(zTreeNode.getId());
                if (role.getResourceCount() == 0) {
                    zTreeNodeRole.setName(role.getRoleName() + "    (" + role.getResourceCount() + "项授权)");
                }


                nodes.add(zTreeNodeRole);
            }
        });
        return nodes;
    }

    @Override
    protected String moduleName() {
        return "role";
    }
}


